package edu.indiana.d2i.vm;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import edu.indiana.d2i.job.HTRCJobConfig;

public class VMPoolManager {
	private List<VMStatus> availableVMs = new ArrayList<VMStatus>();  
	private List<VMStatus> usedVMs = new ArrayList<VMStatus>(); 
	
	public static final Log LOG = LogFactory.getLog(VMPoolManager.class);
	
	public VMPoolManager(VMInfo[] vms) {
		synchronized (availableVMs) {
			for (int i = 0; i < vms.length; i++) {
				availableVMs.add(new VMStatus(null, vms[i], VMStatus.STATUS.NOTASSIGNED));
				LOG.info("Add VM " + vms[i] + " to pool");
			}
		}
	}
	
	public VMInfo[] requestVMs(HTRCJobConfig job) {
		synchronized (availableVMs) {
			int numVM = job.numVM;
			if (availableVMs.size() < numVM) return null;
			
			synchronized (usedVMs) {
				int count = 0;
				VMInfo[] vms = new VMInfo[numVM];
				Iterator<VMStatus> iterator = availableVMs.iterator();
				while (iterator.hasNext() && count < numVM) {
					VMStatus vm = iterator.next();
					vm.status = VMStatus.STATUS.RUNNINGJOB;
					vm.jobid = job.jobID;
					vms[count++] = vm.vminfo;
					usedVMs.add(vm);
					iterator.remove();
					
					LOG.info(vm);
				}				
				return vms;
			}
		}
	}
	
	// change the algorithm and data structure!! use hashmap to speed up!!
	public void releaseVMs(String jobID) {
		synchronized (usedVMs) {
			Iterator<VMStatus> iterator = usedVMs.iterator();
			synchronized (availableVMs) {
				while (iterator.hasNext()) {
					VMStatus vm = iterator.next();
					if (vm.jobid.equals(jobID)) {
						vm.status = VMStatus.STATUS.NOTASSIGNED;
						vm.jobid = null;
						availableVMs.add(vm);
						iterator.remove();
						LOG.info(vm);
					}
				}
			}
		}
	}
	
	public int size() {
		synchronized (availableVMs) {
			return availableVMs.size();
		}
	}
	
	public List<VMStatus> getVMStatus() {
		List<VMStatus> status = new ArrayList<VMStatus>(availableVMs);
		status.addAll(usedVMs);
		return status;
	}
}
